<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div>打开控制台查看结果</div>

    <script>
        console.log('--------标签模板--------');
        alert `hello` // 等同于 alert(['hello'])

        /* 标签模板其实是函数调用的一种特殊形式，此处的alert是函数，紧跟在后面的模板字符串就是它的参数 */

        /* 但如果模板字符串有变量，就不是简单的调用，而是会先将模板字符串先处理成多个参数，再调用函数 */
        let a = 5
        let b = 10
        alert `hello ${ a + b} , word ${ a * b }`
        tag(`hello ${ a + b} , word ${ a * b }`)
        // 此处的tag等同于 
        // tag([`hello ', ', word ', ''],15,50)
        /* 在这里，模板字符串前有一个tag，这个tag是一个函数，整个表达式的返回值就是tag函数处理模板字符串后返回的值，返回结果可以看上面alert打印的内容 */
        // 实际上转换成了
        function tag(stringArr, value1, value2) {
            // ......
        }
        // 或者
        function tag(stringArr, ...values) {
            console.log(stringArr, values);
            // ......
        }
        tag(`hello ${ a + b} , word ${ a * b }`)
        /* 
        1、tag函数的第一个参数是一个数组，整个数组是模板字符串中没有变量替换的部分。
        2、变量的替换，只发生在数组的第一个成员于第二个成员之间，第二个成员与第三个成员之间，以此类推。
        3、tag函数的其他参数，都是模板字符串各个变量被替换后的值。这里的模板字符串有两个参数，所以这里会接收 value1, value2 两个参数。
        例如：
        第一个参数：[`hello ', ', word ', '']
        第二个参数：15
        第三个参数：50
        其实也就是 tag([`hello ', ', word ', ''],15,50)
        */

        console.log('---------例子----------');

        let total = 30;
        let msg = passthru `The total is ${total} (${total*1.05} with tax)`;

        function passthru(literals) {
            //console.log(literals); //  ['The total is ', ' (', ' with tax)', raw: Array(3)]
            let result = ''
            let i = 0
            while (i < literals.length) {
                result += literals[i++];
                if (i < arguments.length) {
                    /* 
                    0:['The total is ', ' (', ' with tax)', raw: Array(3)]
                    1 : 30
                    2 : 31.5
                    */
                    console.log(arguments); // 参数的数组  
                    result += arguments[i]
                }
            }
            return result
        }
        /*  
        1、进来之后，外层循环拿非参数的数组，也就是第一个参数的数组
        2、内层的判断取参数的值
        3、while遍历，如果参数为true则循环遍历，直到false终止
        遍历内容如下：
        The total is 
        30
         (
        31.5
        with tax)
        */
        console.log(msg); // The total is 30 (31.5 with tax)

        /* 模板标签的一个重要应用就是防止用户恶意输入，过滤HTML字符串 */

        // 此处编译器会自动格式化,所以用 sxxxcript 代替 script
        let sender = '<sxxxcript>alert("恶意代码")</sxxxcript>'

        function SaferHTML(templateData) {
            let s = templateData[0]
            for (let i = 1; i < arguments.length; i++) {
                let arg = String(arguments[i])
                s += arg.replace(/&/g, "&amp")
                    .replace(/</g, "&lt")
                    .replace(/>/g, "&gt")
                // 过滤 转义 &为&amp字符;  <为&lt字符;  >为&gt字符;
                s += templateData[i]

            }
            return s
        }
        let message = SaferHTML `<p>${sender}个人信息</p>`
        console.log(message);
        // 打印 <p>&lt;script&gt;alert("恶意代码")&lt;/script&gt; 个人信息</p>

        /* 标签模板可以做多语言转换（国际化） */
        i18n `Welcome to ${userName}, you are visitor number ${visitorNumber}!`

        /* 甚至可以在标签模板嵌套其他语言 */
        // jsx `
        //     <div>
        //         <input
        //         ref='input'
        //         onChange='${this.handleChange}'
        //         defaultValue='${this.state.value}' />
        //         ${this.state.value}
        //     </div>
        //     `
        // 此处就是通过jsx函数，将DOM字符串转换为React对象


        /* 模板处理函数的第一个参数，也就是非参数的模板字符串数组，有一个raw属性 */
        console.log(`abc`) // ['abc',raw:Array[1]]
        // 这个raw保存的是转义后的原字符串
    </script>
</body>

</html>